﻿// // ******************************************************************
// //       /\ /|       @file       SupReaderHelper.cs
// //       \ V/        @brief      await29
// //       | "")       @author     Await, 285283010@qq.com
// //       /  |
// //      /  \\        @Modified   2025-01-10 18:01
// //    *(__\_\        @Copyright  Copyright (c) , 2025-01-07 20:01 Await
// // ******************************************************************

using System.Diagnostics;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using System.Runtime.InteropServices;

namespace AutomaticSubtitles.Service.Infrastructure.Helper;

public class SupReaderHelper : IDisposable
{
    private readonly string _ffmpegPath;
    private readonly string _filePath;
    private readonly string _tempDir;

    public SupReaderHelper(string filePath)
    {
        _filePath = filePath;
        // _tempDir = Path.Combine(Path.GetTempPath(), "SupReader", Guid.NewGuid().ToString());
        _tempDir = Path.Combine(Path.GetDirectoryName(filePath), "SupReader", Guid.NewGuid().ToString());
        Directory.CreateDirectory(_tempDir);

        // 根据操作系统设置 FFmpeg 路径
        _ffmpegPath = GetFfmpegPath();
    }

    public void Dispose()
    {
        try
        {
            if (Directory.Exists(_tempDir)) Directory.Delete(_tempDir, true);
        }
        catch
        {
            // 忽略清理临时文件时的错误
        }
    }

    private string GetFfmpegPath()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return "ffmpeg.exe";
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            return "ffmpeg";
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            return "ffmpeg";
        else
            throw new PlatformNotSupportedException("Unsupported operating system");
    }

    public async IAsyncEnumerable<string> ReadFilePngFramesAsync()
    {
        try
        {
            await ExtractFramesToImages();

            var imageFiles = Directory.GetFiles(_tempDir, "frame_*.png").OrderBy(f => f).ToList();
            foreach (var t in imageFiles)
                yield return t;
        }
        finally
        {
            // 清理临时文件
            if (Directory.Exists(_tempDir)) Directory.Delete(_tempDir, true);
        }
    }

    public async IAsyncEnumerable<SupFrame> ReadFramesAsync()
    {
        try
        {
            // 1. 首先将 SUP 转换为图片序列
            await ExtractFramesToImages();

            // 2. 读取时间信息文件
            var timeInfo = await File.ReadAllLinesAsync(Path.Combine(_tempDir, "timestamps.txt"));
            var timestamps = ParseTimestamps(timeInfo);

            // 3. 处理每一帧
            var imageFiles = Directory.GetFiles(_tempDir, "frame_*.png").OrderBy(f => f).ToList();

            for (var i = 0; i < imageFiles.Count; i++)
            {
                var frame = new SupFrame
                {
                    Index = i + 1,
                    StartTime = timestamps[i].start,
                    EndTime = timestamps[i].end,
                    Image = await Image.LoadAsync<Rgba32>(imageFiles[i])
                };

                yield return frame;
            }
        }
        finally
        {
            // 清理临时文件
            if (Directory.Exists(_tempDir)) Directory.Delete(_tempDir, true);
        }
    }

    private List<(TimeSpan start, TimeSpan end)> ParseTimestamps(string[] lines)
    {
        var timestamps = new List<(TimeSpan start, TimeSpan end)>();
        var timestampPattern = @"pts_time:([\d.]+)"; // 匹配 pts_time:数字.数字 格式

        for (var i = 0; i < lines.Length - 1; i++)
            if (lines[i].Contains("pts_time"))
            {
                var match = System.Text.RegularExpressions.Regex.Match(lines[i], timestampPattern);
                if (match.Success)
                {
                    var startTime = TimeSpan.FromSeconds(double.Parse(match.Groups[1].Value));
                    var endTime = i < lines.Length - 2
                        ? TimeSpan.FromSeconds(double.Parse(System.Text.RegularExpressions.Regex.Match(lines[i + 1], timestampPattern).Groups[1].Value))
                        : startTime + TimeSpan.FromSeconds(3); // 最后一帧默认显示3秒

                    timestamps.Add((startTime, endTime));
                }
            }

        return timestamps;
    }

    private async Task ExtractFramesToImages()
    {
        var processStartInfo = new ProcessStartInfo
        {
            FileName = _ffmpegPath,
            Arguments = $"-i \"{_filePath}\" " +
                        $"-filter_complex \"[0:s:0]scale=1920:1080\" " +
                        $"-vsync 0 " +
                        $"-loglevel debug " +
                        // 使用 %d 和 %pts 来获取更精确的显示时间戳
                        $"-frame_pts 1 " +
                        $"-metadata:s:v:0 ts_packetize=1 " +
                        $"\"{Path.Combine(_tempDir, "frame_%d_pts_%pts.png")}\"",
            RedirectStandardError = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        using var process = Process.Start(processStartInfo);
        if (process == null)
            throw new Exception("Failed to start FFmpeg process");

        // 将错误输出重定向到文件
        using (var errorWriter = new StreamWriter(Path.Combine(_tempDir, "timestamps.txt")))
        {
            await process.StandardError.PipeToAsync(errorWriter);
        }

        await process.WaitForExitAsync();

        if (process.ExitCode != 0)
            throw new Exception($"FFmpeg process failed with exit code {process.ExitCode}");
    }

    // private async Task ExtractFramesToImages()
    // {
    //     var processStartInfo = new ProcessStartInfo
    //     {
    //         FileName = _ffmpegPath,
    //         Arguments = $"-i \"{_filePath}\" " +
    //                     $"-filter_complex \"[0:s:0]scale=1920:1080\" " +
    //                     $"-vsync 0 " +
    //                     $"\"{Path.Combine(_tempDir, "frame_%d.png")}\"",
    //         RedirectStandardError = true,
    //         UseShellExecute = false,
    //         CreateNoWindow = true
    //     };
    //
    //     using var process = Process.Start(processStartInfo);
    //     if (process == null)
    //         throw new Exception("Failed to start FFmpeg process");
    //
    //     // 将错误输出重定向到文件
    //     using (var errorWriter = new StreamWriter(Path.Combine(_tempDir, "timestamps.txt")))
    //     {
    //         await process.StandardError.PipeToAsync(errorWriter);
    //     }
    //
    //     await process.WaitForExitAsync();
    //
    //     if (process.ExitCode != 0)
    //         throw new Exception($"FFmpeg process failed with exit code {process.ExitCode}");
    // }


    public class SupFrame
    {
        public int           Index     { get; set; }
        public TimeSpan      StartTime { get; set; }
        public TimeSpan      EndTime   { get; set; }
        public Image<Rgba32> Image     { get; set; }

        public void Dispose()
        {
            Image?.Dispose();
        }
    }
}